using System.Collections.Specialized;
using System.Web.Security;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NMock2;
using NMock2.Actions;
using OTPProvider = Be.Timvw.Framework.Web.Security.OneTimePasswordMembershipProvider;

namespace Be.Timvw.Framework.Web.Tests.Security.OneTimePasswordMembershipProvider
{
    [TestClass]
    public class WhenUsing
    {
        #region Infrastructure for all tests in this class

        private IMembershipProvider membershipProvider;
        private Mockery mocks;

        [TestInitialize]
        public void Initialize()
        {
            this.mocks = new Mockery();
            this.membershipProvider = (IMembershipProvider) this.mocks.NewMock(typeof(IMembershipProvider));
            MockMembershipProviderWrapper.MembershipProvider = this.membershipProvider;
        }

        [TestCleanup]
        public void Cleanup()
        {
            this.mocks.VerifyAllExpectationsHaveBeenMet();
            this.mocks = null;
        }

        public NameValueCollection GetConfig()
        {
            NameValueCollection config = new NameValueCollection();
            config.Add(OTPProvider.ProviderTypeKey, typeof(MockMembershipProviderWrapper).AssemblyQualifiedName);
            return config;
        }

        public OTPProvider CreateAndInitializeOneTimePasswordMembershipProvider()
        {
            string name = "/";
            return this.CreateAndInitializeOneTimePasswordMembershipProvider(name, this.GetConfig());
        }

        public OTPProvider CreateAndInitializeOneTimePasswordMembershipProvider(string name, NameValueCollection config)
        {
            string expectedName = name;
            NameValueCollection expectedConfig = config;
            Expect.Once.On(this.membershipProvider).Method("Initialize").With(expectedName, expectedConfig);

            OTPProvider otpMembershipProvider = new OTPProvider();
            otpMembershipProvider.Initialize(name, config);
            return otpMembershipProvider;
        }

        #endregion

        #region Tests that verify that calls are dispatched to the provider

        [TestMethod]
        public void ShouldInitializeOnProvider()
        {
            this.CreateAndInitializeOneTimePasswordMembershipProvider();
        }

        [TestMethod]
        public void ShouldSetApplicationNameOnProvider()
        {
            string name = "/test";

            string expectedName = name;
            Expect.Once.On(this.membershipProvider).SetProperty("ApplicationName").To(expectedName);

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            otpMembershipProvider.ApplicationName = name;
        }

        [TestMethod]
        public void ShouldGetApplicationNameOnProvider()
        {
            string name = "/test";

            string expectedName = name;
            Expect.Once.On(this.membershipProvider).GetProperty("ApplicationName").Will(Return.Value(name));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            Assert.AreEqual(expectedName, otpMembershipProvider.ApplicationName);
        }

        [TestMethod]
        public void ShouldGetPasswordStrengthRegularExpressionOnProvider()
        {
            string name = "{}";

            string expectedName = name;
            Expect.Once.On(this.membershipProvider).GetProperty("PasswordStrengthRegularExpression").Will(Return.Value(name));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            Assert.AreEqual(expectedName, otpMembershipProvider.PasswordStrengthRegularExpression);
        }

        [TestMethod]
        public void ShouldGetMinRequiredNonAlphanumericCharactersOnProvider()
        {
            int number = 2;

            int expectedNumber = number;
            Expect.Once.On(this.membershipProvider).GetProperty("MinRequiredNonAlphanumericCharacters").Will(Return.Value(number));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            Assert.AreEqual(expectedNumber, otpMembershipProvider.MinRequiredNonAlphanumericCharacters);
        }

        [TestMethod]
        public void ShouldGetMinRequiredPasswordLengthOnProvider()
        {
            int number = 3;

            int expectedNumber = number;
            Expect.Once.On(this.membershipProvider).GetProperty("MinRequiredPasswordLength").Will(Return.Value(number));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            Assert.AreEqual(expectedNumber, otpMembershipProvider.MinRequiredPasswordLength);
        }

        [TestMethod]
        public void ShouldGetPasswordFormatOnProvider()
        {
            MembershipPasswordFormat passwordFormat = MembershipPasswordFormat.Encrypted;

            MembershipPasswordFormat expectedPasswordFormat = passwordFormat;
            Expect.Once.On(this.membershipProvider).GetProperty("PasswordFormat").Will(Return.Value(passwordFormat));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            Assert.AreEqual(expectedPasswordFormat, otpMembershipProvider.PasswordFormat);
        }

        [TestMethod]
        public void ShouldGetMaxInvalidPasswordAttemptsOnProvider()
        {
            int number = 4;

            int expectedNumber = number;
            Expect.Once.On(this.membershipProvider).GetProperty("MaxInvalidPasswordAttempts").Will(Return.Value(number));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            Assert.AreEqual(expectedNumber, otpMembershipProvider.MaxInvalidPasswordAttempts);
        }

        [TestMethod]
        public void ShouldGetPasswordAttemptWindowOnProvider()
        {
            int number = 5;

            int expectedNumber = number;
            Expect.Once.On(this.membershipProvider).GetProperty("PasswordAttemptWindow").Will(Return.Value(number));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            Assert.AreEqual(expectedNumber, otpMembershipProvider.PasswordAttemptWindow);
        }

        [TestMethod]
        public void ShouldGetEnablePasswordRetrievalOnProvider()
        {
            bool enabled = true;

            bool expectedEnabled = enabled;
            Expect.Once.On(this.membershipProvider).GetProperty("EnablePasswordRetrieval").Will(Return.Value(enabled));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            Assert.AreEqual(expectedEnabled, otpMembershipProvider.EnablePasswordRetrieval);
        }

        [TestMethod]
        public void ShouldGetEnablePasswordResetOnProvider()
        {
            bool enabled = true;

            bool expectedEnabled = enabled;
            Expect.Once.On(this.membershipProvider).GetProperty("EnablePasswordReset").Will(Return.Value(enabled));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            Assert.AreEqual(expectedEnabled, otpMembershipProvider.EnablePasswordReset);
        }

        [TestMethod]
        public void ShouldGetRequiresQuestionAndAnswerOnProvider()
        {
            bool enabled = true;

            bool expectedEnabled = enabled;
            Expect.Once.On(this.membershipProvider).GetProperty("RequiresQuestionAndAnswer").Will(Return.Value(enabled));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            Assert.AreEqual(expectedEnabled, otpMembershipProvider.RequiresQuestionAndAnswer);
        }

        [TestMethod]
        public void ShouldGetRequiresUniqueEmailOnProvider()
        {
            bool enabled = true;

            bool expectedEnabled = enabled;
            Expect.Once.On(this.membershipProvider).GetProperty("RequiresUniqueEmail").Will(Return.Value(enabled));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            Assert.AreEqual(expectedEnabled, otpMembershipProvider.RequiresUniqueEmail);
        }

        [TestMethod]
        public void ShouldCreateUserOnProvider()
        {
            string username = "user";
            string password = "password";
            string email = "email";
            string passwordQuestion = "passwordQuestion";
            string passwordAnswer = "passwordAnser";
            bool isApproved = true;
            object providerUserKey = new object();
            MembershipCreateStatus membershipCreateStatus = MembershipCreateStatus.Success;
            MembershipUser membershipUser = new MockMembershipUser(username);

            MembershipUser expectedResult = membershipUser;
            MembershipCreateStatus expectedmembershipCreateStatus = membershipCreateStatus;
            Expect.Once.On(this.membershipProvider).Method("CreateUser").With(username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, Is.Out).Will(Return.Value(membershipUser), new SetNamedParameterAction("status", membershipCreateStatus));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            MembershipCreateStatus status;
            Assert.AreEqual(expectedResult, otpMembershipProvider.CreateUser(username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, out status));
            Assert.AreEqual(expectedmembershipCreateStatus, status);
        }

        [TestMethod]
        public void ShouldGetUserByProviderKeyOnProvider()
        {
            object providerUserKey = new object();
            bool userIsOnline = true;
            MembershipUser membershipUser = new MockMembershipUser("username");

            MembershipUser expectedResult = membershipUser;
            Expect.Once.On(this.membershipProvider).Method("GetUser").With(providerUserKey, userIsOnline).Will(Return.Value(membershipUser));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            Assert.AreEqual(expectedResult, otpMembershipProvider.GetUser(providerUserKey, userIsOnline));
        }

        [TestMethod]
        public void ShouldGetUserByUserNameOnProvider()
        {
            string username = "username";
            bool userIsOnline = true;
            MembershipUser membershipUser = new MockMembershipUser(username);

            MembershipUser expectedResult = membershipUser;
            Expect.Once.On(this.membershipProvider).Method("GetUser").With(username, userIsOnline).Will(Return.Value(membershipUser));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            Assert.AreEqual(expectedResult, otpMembershipProvider.GetUser(username, userIsOnline));
        }

        [TestMethod]
        public void ShouldUpdateUserOnProvider()
        {
            MembershipUser membershipUser = new MockMembershipUser("username");

            Expect.Once.On(this.membershipProvider).Method("UpdateUser").With(membershipUser);

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            otpMembershipProvider.UpdateUser(membershipUser);
        }

        [TestMethod]
        public void ShouldGetNumberOfUsersOnlineOnProvider()
        {
            int numberOfUsersOnline = 11;

            int expectedNumberOfUsersOnline = numberOfUsersOnline;
            Expect.Once.On(this.membershipProvider).Method("GetNumberOfUsersOnline").Will(Return.Value(numberOfUsersOnline));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            Assert.AreEqual(expectedNumberOfUsersOnline, otpMembershipProvider.GetNumberOfUsersOnline());
        }

        [TestMethod]
        public void ShouldGetGetPasswordOnProvider()
        {
            string password = "password";
            string username = "username";
            string answer = "answer";

            string expectedPassword = password;
            Expect.Once.On(this.membershipProvider).Method("GetPassword").With(username, answer).Will(Return.Value(password));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            Assert.AreEqual(expectedPassword, otpMembershipProvider.GetPassword(username, answer));
        }

        [TestMethod]
        public void ShouldResetPasswordOnProvider()
        {
            string password = "password";
            string username = "username";
            string answer = "answer";

            string expectedPassword = password;
            Expect.Once.On(this.membershipProvider).Method("ResetPassword").With(username, answer).Will(Return.Value(password));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            Assert.AreEqual(expectedPassword, otpMembershipProvider.ResetPassword(username, answer));
        }

        [TestMethod]
        public void ShouldGetUserNameByEmailOnProvider()
        {
            string username = "username";
            string email = "email";

            string expectedUsername = username;
            Expect.Once.On(this.membershipProvider).Method("GetUserNameByEmail").With(email).Will(Return.Value(username));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            Assert.AreEqual(expectedUsername, otpMembershipProvider.GetUserNameByEmail(email));
        }

        [TestMethod]
        public void ShouldUnlockUserOnProvider()
        {
            string username = "username";
            bool result = true;

            bool expectedResult = result;
            Expect.Once.On(this.membershipProvider).Method("UnlockUser").With(username).Will(Return.Value(result));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            Assert.AreEqual(expectedResult, otpMembershipProvider.UnlockUser(username));
        }

        [TestMethod]
        public void ShouldDeleteUserOnProvider()
        {
            string username = "username";
            bool deleteAllRelatedData = true;
            bool result = true;

            bool expectedResult = result;
            Expect.Once.On(this.membershipProvider).Method("DeleteUser").With(username, deleteAllRelatedData).Will(Return.Value(result));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            Assert.AreEqual(expectedResult, otpMembershipProvider.DeleteUser(username, deleteAllRelatedData));
        }

        [TestMethod]
        public void ShouldChangePasswordOnProvider()
        {
            string username = "username";
            string oldPassword = "oldPassword";
            string newPassword = "newPassword";
            bool result = true;

            bool expectedResult = result;
            Expect.Once.On(this.membershipProvider).Method("ChangePassword").With(username, oldPassword, newPassword).Will(Return.Value(result));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            Assert.AreEqual(expectedResult, otpMembershipProvider.ChangePassword(username, oldPassword, newPassword));
        }

        [TestMethod]
        public void ShouldChangePasswordQuestionAndAnswerOnProvider()
        {
            string username = "username";
            string password = "password";
            string newPasswordQuestion = "newPasswordQuestion";
            string newPasswordAnswer = "newPasswordAnswer";
            bool result = true;

            bool expectedResult = result;
            Expect.Once.On(this.membershipProvider).Method("ChangePasswordQuestionAndAnswer").With(username, password, newPasswordQuestion, newPasswordAnswer).Will(Return.Value(result));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            Assert.AreEqual(expectedResult, otpMembershipProvider.ChangePasswordQuestionAndAnswer(username, password, newPasswordQuestion, newPasswordAnswer));
        }

        [TestMethod]
        public void ShouldGetAllUsersOnProvider()
        {
            int pageIndex = 1;
            int pageSize = 1;
            MembershipUserCollection membershipUsers = new MembershipUserCollection();
            membershipUsers.Add(new MockMembershipUser("username"));
            int totalRecords = 1;

            MembershipUserCollection expectedResult = membershipUsers;
            int expectedTotalRecords = totalRecords;

            Expect.Once.On(this.membershipProvider).Method("GetAllUsers").With(pageIndex, pageSize, Is.Out).Will(Return.Value(membershipUsers), new SetNamedParameterAction("totalRecords", totalRecords));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            int actualTotalRecords;
            Assert.AreEqual(expectedResult, otpMembershipProvider.GetAllUsers(pageIndex, pageSize, out actualTotalRecords));
            Assert.AreEqual(expectedTotalRecords, actualTotalRecords);
        }

        [TestMethod]
        public void ShouldFindUsersByNameOnUser()
        {
            string usernameToMatch = "usernameToMatch";
            int pageIndex = 1;
            int pageSize = 1;
            MembershipUserCollection membershipUsers = new MembershipUserCollection();
            membershipUsers.Add(new MockMembershipUser("username"));
            int totalRecords = 1;

            MembershipUserCollection expectedResult = membershipUsers;
            int expectedTotalRecords = totalRecords;

            Expect.Once.On(this.membershipProvider).Method("FindUsersByName").With(usernameToMatch, pageIndex, pageSize, Is.Out).Will(Return.Value(membershipUsers), new SetNamedParameterAction("totalRecords", totalRecords));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            int actualTotalRecords;
            Assert.AreEqual(expectedResult, otpMembershipProvider.FindUsersByName(usernameToMatch, pageIndex, pageSize, out actualTotalRecords));
            Assert.AreEqual(expectedTotalRecords, actualTotalRecords);
        }

        [TestMethod]
        public void ShouldFindUsersByEmailOnProvider()
        {
            string emailToMatch = "emailToMatch";
            int pageIndex = 1;
            int pageSize = 1;
            MembershipUserCollection membershipUsers = new MembershipUserCollection();
            membershipUsers.Add(new MockMembershipUser("username"));
            int totalRecords = 1;

            MembershipUserCollection expectedResult = membershipUsers;
            int expectedTotalRecords = totalRecords;

            Expect.Once.On(this.membershipProvider).Method("FindUsersByEmail").With(emailToMatch, pageIndex, pageSize, Is.Out).Will(Return.Value(membershipUsers), new SetNamedParameterAction("totalRecords", totalRecords));

            OTPProvider otpMembershipProvider = this.CreateAndInitializeOneTimePasswordMembershipProvider();
            int actualTotalRecords;
            Assert.AreEqual(expectedResult, otpMembershipProvider.FindUsersByEmail(emailToMatch, pageIndex, pageSize, out actualTotalRecords));
            Assert.AreEqual(expectedTotalRecords, actualTotalRecords);
        }

        #endregion
    }
}